﻿using System;
using System.Web.Mvc;
using Application.MainModule.UserManagement;
using Presentation.Web.UI.Attibutes;
using Presentation.Web.UI.Authentication.FormsAuthenticationParty;
using Presentation.Web.ViewModels;
using System.Web.Security;
using System.Security.Principal;
using System.Globalization;

namespace Presentation.Web.UI.Controllers
{
    [HandleErrorWithELMAH]
    public class AccountController : Controller
    {
        private readonly IFormsAuthentication _formsAuthentication;
        private readonly IUserManagementService _userManagementService;

        public AccountController(IFormsAuthentication formsAuthentication, IUserManagementService userManagementService)
        {
            _formsAuthentication = formsAuthentication;
            _userManagementService = userManagementService;
        }

        public ActionResult LogOn()
        {

            return View();
        }

        [HttpPost]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
            Justification = "Needs to take same parameter type as Controller.Redirect()")]
        public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (ValidateLogOn(model.UserName, model.Password))
                {
                    // Make sure we have the username with the right capitalization
                    // since we do case sensitive checks for OpenID Claimed Identifiers later.
                    var user = _userManagementService.GetCanonicalUser(model.UserName);

                    _formsAuthentication.SignIn(UserMapping.ToServiceUser(user), model.RememberMe);

                    // Make sure we only follow relative returnUrl parameters to protect against having an open redirector
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "The user name or password provided is incorrect.");
                }
            }
            return View(model);
        }

        public ActionResult LogOff()
        {
            _formsAuthentication.SignOut();
            return RedirectToAction("Index", "Home");
        }

        public ActionResult Register()
        {

            ViewBag.PasswordLength = Configuration.PresentationSection.Current.MembershipProvider.MinPasswordLength;
            return View();
        }

        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                ViewBag.PasswordLength = Configuration.PresentationSection.Current.MembershipProvider.MinPasswordLength;
                if (ValidateRegistration(model.UserName, model.Email, model.Password, model.ConfirmPassword))
                {
                    // Attempt to register the user
                     var user = _userManagementService.CreateUser(model.UserName, model.Password, model.Email);

                     if (user != null)
                    {
                        _formsAuthentication.SignIn(UserMapping.ToServiceUser(user), false /* createPersistentCookie */);
                        return RedirectToAction("Index", "Home");
                    }
                    else
                    {
                        ModelState.AddModelError("", "some error");
                    }
                }
            }
            return View(model);
        }

        [Authorize]
        public ActionResult ChangePassword()
        {

            ViewBag.PasswordLength = Configuration.PresentationSection.Current.MembershipProvider.MinPasswordLength;

            return View();
        }

        [Authorize]
        [HttpPost]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "Exceptions result in password not being changed.")]
        public ActionResult ChangePassword(string currentPassword, string newPassword, string confirmPassword)
        {

            ViewBag.PasswordLength = Configuration.PresentationSection.Current.MembershipProvider.MinPasswordLength;

            if (!ValidateChangePassword(currentPassword, newPassword, confirmPassword))
            {
                return View();
            }

            try
            {
                if (_userManagementService.ChangePassword(User.Identity.Name, currentPassword, newPassword))
                {
                    return RedirectToAction("ChangePasswordSuccess");
                }
                else
                {
                    ModelState.AddModelError("_FORM", "The current password is incorrect or the new password is invalid.");
                    return View();
                }
            }
            catch
            {
                ModelState.AddModelError("_FORM", "The current password is incorrect or the new password is invalid.");
                return View();
            }
        }

        public ActionResult ChangePasswordSuccess()
        {

            return View();
        }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.User.Identity is WindowsIdentity)
            {
                throw new InvalidOperationException("Windows authentication is not supported.");
            }
        }

        #region Validation Methods

        private bool ValidateChangePassword(string currentPassword, string newPassword, string confirmPassword)
        {
            if (String.IsNullOrEmpty(currentPassword))
            {
                ModelState.AddModelError("currentPassword", "You must specify a current password.");
            }
            if (newPassword == null || newPassword.Length < Configuration.PresentationSection.Current.MembershipProvider.MinPasswordLength)
            {
                ModelState.AddModelError("newPassword",
                    String.Format(CultureInfo.CurrentCulture,
                         "You must specify a new password of {0} or more characters.",
                         Configuration.PresentationSection.Current.MembershipProvider.MinPasswordLength));
            }

            if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal))
            {
                ModelState.AddModelError("_FORM", "The new password and confirmation password do not match.");
            }

            return ModelState.IsValid;
        }

        private bool ValidateLogOn(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("username", "You must specify a username.");
            }
            if (String.IsNullOrEmpty(password))
            {
                ModelState.AddModelError("password", "You must specify a password.");
            }
            if (!_userManagementService.ValidateUser(userName, password))
            {
                ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
            }

            return ModelState.IsValid;
        }

        private bool ValidateRegistration(string userName, string email, string password, string confirmPassword)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("username", "You must specify a username.");
            }
            if (String.IsNullOrEmpty(email))
            {
                ModelState.AddModelError("email", "You must specify an email address.");
            }
            if (password == null || password.Length < Configuration.PresentationSection.Current.MembershipProvider.MinPasswordLength)
            {
                ModelState.AddModelError("password",
                    String.Format(CultureInfo.CurrentCulture,
                         "You must specify a password of {0} or more characters.",
                         Configuration.PresentationSection.Current.MembershipProvider.MinPasswordLength));
            }
            if (!String.Equals(password, confirmPassword, StringComparison.Ordinal))
            {
                ModelState.AddModelError("_FORM", "The new password and confirmation password do not match.");
            }
            return ModelState.IsValid;
        }

        #endregion
    }
}
